package com.sh.data.engine.domain.common.model.domain;

import gudusoft.gsqlparser.EDbVendor;
import gudusoft.gsqlparser.dlineage.dataflow.model.RelationshipType;
import gudusoft.gsqlparser.dlineage.dataflow.model.xml.*;
import gudusoft.gsqlparser.dlineage.util.Pair3;
import gudusoft.gsqlparser.util.SQLUtil;
import org.apache.commons.lang.StringEscapeUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


public class DataFlowGraph {


    public Pair3<String, Boolean, Set<String>> generateDataFlowGraph(EDbVendor vendor,
                                                                     dataflow dataflow1, boolean showLinkOnly, boolean hideColumn,
                                                                     List<RelationshipType> relationshipTypes, String serverName, String databaseName,
                                                                     String schemaName, String tableName, Map<String, String> tooltipMap) {
        try {
            return convertMetaInfoToGraphXML(vendor, dataflow1, showLinkOnly, hideColumn,
                relationshipTypes, serverName, databaseName, schemaName, tableName, tooltipMap);
        } catch (Exception e2) {

            return null;
        }
    }

    private List<Object> nodes = new ArrayList();

    private Set<relationship> linkRelations = new HashSet<>();

    private List<Object> linkIds = new ArrayList();

    public List<Object> getNodes() {
        return this.nodes;
    }

    public List<relationship> getRelationships() {
        return new ArrayList<>(this.linkRelations);
    }

    private Pair3<String, Boolean, Set<String>> convertMetaInfoToGraphXML(EDbVendor vendor,
                                                                          dataflow dataflow1, boolean showLinkOnly, boolean hideColumn,
                                                                          List<RelationshipType> relationshipTypes, String serverName, String databaseName,
                                                                          String schemaName, String tableName, Map<String, String> tooltipMap) throws IOException {
        this.nodes.clear();
        this.linkIds.clear();
        this.linkRelations.clear();
        boolean containGroup = false;
        String columnContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream(
            "/column.template"), false);
        String tableContent = SQLUtil.getInputStreamContent(
            DataFlowGraph.class.getResourceAsStream(
                "/table.template"), false);
        String linkContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream(
            "/link.template"), false);
        String graphContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream(
            "/graph.template"), false);
        StringBuffer tableFullBuffer = new StringBuffer();
        List<table> tables = new ArrayList<>();
        if (dataflow1.getTables() != null) {
            tables.addAll(dataflow1.getTables());
        }
        if (!relationshipTypes.contains(RelationshipType.er)) {
            if (dataflow1.getViews() != null) {
                tables.addAll(dataflow1.getViews());
            }
            if (dataflow1.getStages() != null) {
                tables.addAll(dataflow1.getStages());
            }
            if (dataflow1.getSequences() != null) {
                tables.addAll(dataflow1.getSequences());
            }
            if (dataflow1.getDatasources() != null) {
                tables.addAll(dataflow1.getDatasources());
            }
            if (dataflow1.getDatabases() != null) {
                tables.addAll(dataflow1.getDatabases());
            }
            if (dataflow1.getSchemas() != null) {
                tables.addAll(dataflow1.getSchemas());
            }
            if (dataflow1.getStreams() != null) {
                tables.addAll(dataflow1.getStreams());
            }
            if (dataflow1.getPaths() != null) {
                tables.addAll(dataflow1.getPaths());
            }
            if (dataflow1.getVariables() != null) {
                tables.addAll(dataflow1.getVariables());
            }
            if (dataflow1.getResultsets() != null) {
                tables.addAll(dataflow1.getResultsets());
            }
        }
        Map<String, table> tableMap = new HashMap<>();
        for (table table : tables) {
            tableMap.put(table.getId(), table);
        }
        Set<String> relationshipTableIds = new HashSet<>();
        for (relationship relationship : dataflow1.getRelationships()) {
            if ("call".equals(relationship.getType())) {
                continue;
            }
            if (relationship.getTarget().getParent_id() != null) {
                relationshipTableIds.add(relationship.getTarget().getParent_id());
            } else {
                relationshipTableIds.add(relationship.getTarget().getId());
            }
            if (relationship.getSources() != null) {
                for (sourceColumn sourceColumn : relationship.getSources()) {
                    if (sourceColumn.getParent_id() != null) {
                        relationshipTableIds.add(sourceColumn.getParent_id());
                        continue;
                    }
                    relationshipTableIds.add(sourceColumn.getId());
                }
            }
        }
        Iterator<String> tableIter = tableMap.keySet().iterator();
        if (relationshipTypes.contains(RelationshipType.er)) {
            while (tableIter.hasNext()) {
                String tableId = tableIter.next();
                if (!relationshipTableIds.contains(tableId)) {
                    table tb = tableMap.get(tableId);
                    if ((!SQLUtil.isEmpty(tableName) && !tableName.equalsIgnoreCase(tb.getName())) || (
                        !SQLUtil.isEmpty(databaseName) && !databaseName.equalsIgnoreCase(tb.getDatabase()))
                        || (
                        !SQLUtil.isEmpty(schemaName) && !schemaName.equalsIgnoreCase(tb.getSchema())) || (
                        !SQLUtil.isEmpty(serverName) && !serverName.equalsIgnoreCase(tb.getServer()))) {
                        tableIter.remove();
                    }
                }
            }
        } else {
            while (tableIter.hasNext()) {
                if (!relationshipTableIds.contains(tableIter.next())) {
                    tableIter.remove();
                }
            }
        }
        Map<String, Map<String, List<column>>> tableColumns = new HashMap<>();
        Set<String> columnSet = new HashSet<>();
        Set<String> linkColumnSet = new HashSet<>();
        Map<String, process> processMap = new HashMap<>();
        for (process process : dataflow1.getProcesses()) {
            processMap.put(process.getId(), process);
        }
        if (dataflow1.getProcesses() != null) {
            Iterator<String> processIter = processMap.keySet().iterator();
            while (processIter.hasNext()) {
                if (!relationshipTableIds.contains(processIter.next())) {
                    processIter.remove();
                }
            }
            processIter = processMap.keySet().iterator();
            while (processIter.hasNext()) {
                process process = processMap.get(processIter.next());
                String tableId = "table-" + process.getId();
                columnSet.add(tableId);
                this.nodes.add(process);
                String content = new String(tableContent);
                content = content.replace("{tableId}", "table-" + process.getId());
                String tableLabel = process.getName();
                if (tableLabel.length() > 25) {
                    String shortLabel = getShortLabel(tableLabel, 25);
                    if (tooltipMap != null) {
                        tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
                    }
                    tableLabel = shortLabel;
                }
                content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
                StringBuffer columnBuffer = new StringBuffer();
                String columnId = "column-" + process.getId();
                String content1 = new String(columnContent);
                content1 = content1.replace("{columnId}", columnId);
                content1 = content1.replace("{columnPosY}", "0");
                content1 = content1.replace("{columnLabel}", "hide-table-column");
                content1 = content1.replace("height=\"16\"", "height=\"0\"");
                columnBuffer.append(content1).append("\n");
                content = content.replace("{columns}", columnBuffer.toString());
                content = content.replace("{contentColor}", "#9999ff");
                content = content.replace("{labelColor}", "#DBDADA");
                tableFullBuffer.append(content).append("\n");
            }
        }
        tableIter = tableMap.keySet().iterator();
        while (tableIter.hasNext()) {
            table currentTable = tableMap.get(tableIter.next());
            this.nodes.add(currentTable);
            String tableId = "table-" + currentTable.getId();
            columnSet.add(tableId);
            StringBuffer columnBuffer = new StringBuffer();
            if (currentTable.isTable() || currentTable.isView() || currentTable.isCursor()
                || currentTable.isDatabaseType() || currentTable.isSchemaType() || currentTable.isStage()
                || currentTable.isSequence() || currentTable.isDataSource() || currentTable.isStream()
                || currentTable.isFile() || currentTable.isVariable()) {
                Map<String, List<column>> columnMap = new LinkedHashMap<>();
                tableColumns.put(currentTable.getId(), columnMap);
                for (int k = 0; k < currentTable.getColumns().size(); k++) {
                    column column = currentTable.getColumns().get(k);
                    String columnLabel = column.getName();
                    if (!relationshipTypes.contains(RelationshipType.er) || (
                        !columnLabel.equalsIgnoreCase("*") && !columnLabel.equalsIgnoreCase(
                            "relationRows"))) {
                        List<column> columns;
                        if (!columnMap.containsKey(columnLabel)) {
                            columns = new ArrayList<>();
                            columnMap.put(columnLabel, columns);
                        } else {
                            columns = columnMap.get(columnLabel);
                        }
                        columns.add(column);
                    }
                }
                Iterator<Map.Entry<String, List<column>>> iterator = columnMap.entrySet().iterator();
                for (int i = 0; i < columnMap.size(); i++) {
                    Map.Entry<String, List<column>> entry = iterator.next();
                    this.nodes.add(entry.getValue());
                    String str1 = columnContent;
                    String columnId = "column-" + currentTable.getId() + "-index-" + i;
                    if (!columnSet.contains(columnId)) {
                        columnSet.add(columnId);
                        str1 = str1.replace("{columnId}", columnId);
                        str1 = str1.replace("{columnPosY}",
                            String.valueOf(35 * i));
                        String columnLabel = entry.getKey();
                        if (columnLabel.length() > 25) {
                            String shortLabel = getShortLabel(columnLabel, 25);
                            if (tooltipMap != null) {
                                tooltipMap.put(shortLabel.replace("\r\n", "\n")
                                    .replace("\n", " "), columnLabel);
                            }
                            columnLabel = shortLabel;
                        }
                        str1 = str1.replace("{columnLabel}",
                            StringEscapeUtils.escapeXml(columnLabel));
                        columnBuffer.append(str1).append("\n");
                    }
                }
            } else {
                for (int k = 0; k < currentTable.getColumns().size(); k++) {
                    column column = currentTable.getColumns().get(k);
                    this.nodes.add(column);
                    String str1 = new String(columnContent);
                    String columnParentId = currentTable.getId();
                    String columnId = column.getId();
                    columnId = convertColumnId(tableColumns, columnId, columnParentId);
                    columnId = "column-" + columnId;
                    if (!columnSet.contains(columnId)) {
                        columnSet.add(columnId);
                        str1 = str1.replace("{columnId}", columnId);
                        str1 = str1.replace("{columnPosY}",
                            String.valueOf(35 * k));
                        String columnLabel = column.getName();
                        if (columnLabel.length() > 25) {
                            String shortLabel = getShortLabel(columnLabel, 25);
                            if (tooltipMap != null) {
                                tooltipMap.put(shortLabel.replace("\r\n", "\n")
                                    .replace("\n", " "), columnLabel);
                            }
                            columnLabel = shortLabel;
                        }
                        str1 = str1.replace("{columnLabel}",
                            StringEscapeUtils.escapeXml(columnLabel));
                        columnBuffer.append(str1).append("\n");
                    }
                }
            }
            String content = new String(tableContent);
            content = content.replace("{tableId}", "table-" + currentTable
                .getId());
            String tableLabel = currentTable.getName();
            if (tableLabel.length() > 25) {
                String shortLabel = getShortLabel(tableLabel, 25);
                if (tooltipMap != null) {
                    tooltipMap.put(shortLabel.replace("\r\n", "\n")
                        .replace("\n", " "), tableLabel);
                }
                tableLabel = shortLabel;
            }
            if (columnBuffer.length() == 0) {
                String columnId = "column-" + currentTable.getId();
                String content1 = new String(columnContent);
                content1 = content1.replace("{columnId}", columnId);
                content1 = content1.replace("{columnPosY}", "0");
                content1 = content1.replace("{columnLabel}", "hide-table-column");
                content1 = content1.replace("height=\"16\"", "height=\"0\"");
                columnBuffer.append(content1).append("\n");
            }
            content = content.replace("{tableLabel}",
                StringEscapeUtils.escapeXml(tableLabel));
            String columnString = columnBuffer.toString();
            if (hideColumn) {
                columnString = columnString.replace("height=\"16\"", "height=\"0\"");
            }
            content = content.replace("{columns}", columnString);
            if (currentTable.isView()) {
                content = content.replace("{contentColor}", "#ff99cc");
                content = content.replace("{labelColor}", "#ffccff");
            } else if (currentTable.isStage()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isSequence()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isDataSource()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isDatabaseType()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isSchemaType()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isStream()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isFile()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isCursor()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isVariable()) {
                content = content.replace("{contentColor}", "#87CEFA");
                content = content.replace("{labelColor}", "#87CEFA");
            } else if (currentTable.isResultSet()) {
                content = content.replace("{contentColor}", "#009944");
                content = content.replace("{labelColor}", "#aaffcc");
            } else {
                content = content.replace("{contentColor}", "#9999ff");
                content = content.replace("{labelColor}", "#DBDADA");
            }
            tableFullBuffer.append(content).append("\n");
            containGroup = true;
        }
        StringBuffer linkBuffer = new StringBuffer();
        List<relationship> relationships = dataflow1.getRelationships();
        if (relationshipTypes.contains(RelationshipType.join)) {
            relationships = (List<relationship>) relationships.stream()
                .filter(t -> (t.getType().equals("join") || t.getType().equals("fdd")))
                .collect(Collectors.toList());
        }
        if (relationships != null) {
            List<String> links = new ArrayList<>();
            for (int i = 0; i < relationships.size(); i++) {
                relationship relationship = relationships.get(i);
                if (!"call".equals(relationship.getType())) {
                    if (relationshipTypes.contains(RelationshipType.valueOf(relationship.getType())) || (
                        relationshipTypes.contains(RelationshipType.join) && relationship
                            .getType()
                            .equals(RelationshipType.fdd.name()) &&
                            traceJoin(relationship, relationships, tableColumns, 0))) {
                        targetColumn target = relationship.getTarget();
                        String targetColumnId = target.getId();
                        String targetParentId = target.getParent_id();
                        targetColumnId = convertColumnId(tableColumns, targetColumnId, targetParentId);
                        if (targetParentId == null) {
                            targetColumnId = target.getTarget_id();
                        }
                        if (relationship.getSources() != null) {
                            List<sourceColumn> linkTables = relationship.getSources();
                            for (int k = 0; k < linkTables.size(); k++) {
                                sourceColumn source = linkTables.get(k);
                                String sourceColumnId = source.getId();
                                String sourceParentId = source.getParent_id();
                                sourceColumnId = convertColumnId(tableColumns, sourceColumnId, sourceParentId);
                                if (sourceParentId == null) {
                                    sourceColumnId = source.getSource_id();
                                }
                                String content = linkContent;
                                if (relationship.getType()
                                    .equals(RelationshipType.join.name())) {
                                    content = content.replace("type=\"line\"", "type=\"dashed\"");
                                }
                                String sourceId = "column-" + sourceColumnId;
                                if (sourceColumnId != null && sourceColumnId.indexOf("-") == -1) {
                                    sourceId = "table-" + sourceColumnId;
                                }
                                String targetId = "column-" + targetColumnId;
                                if (targetColumnId != null && targetColumnId.indexOf("-") == -1) {
                                    targetId = "table-" + targetColumnId;
                                }
                                content = content.replace("{sourceId}", sourceId);
                                content = content.replace("{targetId}", targetId);
                                if (columnSet.contains(sourceId) && columnSet
                                    .contains(targetId)) {
                                    String temp = content;
                                    if (!links.contains(temp)) {
                                        links.add(temp);
                                        linkColumnSet.add(sourceId);
                                        linkColumnSet.add(targetId);
                                        String linkId = "link_" + relationship.getId() + "_" + sourceColumnId + "_"
                                            + targetColumnId;
                                        content = content.replace("{linkId}", linkId);
                                        this.linkIds.add(linkId);
                                        this.linkRelations.add(relationship);
                                        linkBuffer.append(content).append("\n");
                                    } else {
                                        this.linkRelations.add(relationship);
                                    }
                                } else {
                                    System.err.println("Can't get link_" + relationship

                                        .getId() + "_" + sourceColumnId + "_" + targetColumnId);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (showLinkOnly) {
            this.nodes.clear();
            StringBuffer tableLinkBuffer = new StringBuffer();
            int showColumnCount = 0;
            if (dataflow1.getProcesses() != null) {
                Iterator<String> processIter = processMap.keySet().iterator();
                while (processIter.hasNext()) {
                    process process = processMap.get(processIter.next());
                    if (!linkColumnSet.contains("table-" + process.getId())) {
                        continue;
                    }
                    this.nodes.add(process);
                    String tableId = "table-" + process.getId();
                    columnSet.add(tableId);
                    String content = new String(tableContent);
                    content = content.replace("{tableId}", "table-" + process.getId());
                    String tableLabel = process.getName();
                    if (tableLabel.length() > 25) {
                        String shortLabel = getShortLabel(tableLabel, 25);
                        if (tooltipMap != null) {
                            tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
                        }
                        tableLabel = shortLabel;
                    }
                    content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
                    StringBuffer columnBuffer = new StringBuffer();
                    String columnId = "column-" + process.getId();
                    String content1 = new String(columnContent);
                    content1 = content1.replace("{columnId}", columnId);
                    content1 = content1.replace("{columnPosY}", "0");
                    content1 = content1.replace("{columnLabel}", "hide-table-column");
                    content1 = content1.replace("height=\"16\"", "height=\"0\"");
                    columnBuffer.append(content1).append("\n");
                    content = content.replace("{columns}", columnBuffer.toString());
                    content = content.replace("{contentColor}", "#9999ff");
                    content = content.replace("{labelColor}", "#DBDADA");
                    tableFullBuffer.append(content).append("\n");
                    tableLinkBuffer.append(content).append("\n");
                }
            }
            tableIter = tableMap.keySet().iterator();
            while (tableIter.hasNext()) {
                table currentTable = tableMap.get(tableIter.next());
                if ((currentTable.getColumns() == null || currentTable.getColumns().isEmpty()) &&
                    !linkColumnSet.contains("table-" + currentTable.getId())) {
                    continue;
                }
                boolean removeTable = !linkColumnSet.contains("table-" + currentTable.getId());
                this.nodes.add(currentTable);
                StringBuffer columnBuffer = new StringBuffer();
                if (currentTable.isTable() || currentTable.isView() || currentTable.isCursor()
                    || currentTable.isDatabaseType() || currentTable.isSchemaType()
                    || currentTable.isStage() || currentTable.isSequence() || currentTable.isDataSource()
                    || currentTable.isStream() || currentTable.isFile() || currentTable.isVariable()) {
                    Map<String, List<column>> columnMap = new LinkedHashMap<>();
                    for (int k = 0; k < currentTable.getColumns().size(); k++) {
                        List<column> columns;
                        column column = currentTable.getColumns().get(k);
                        String columnLabel = column.getName();
                        if (!columnMap.containsKey(columnLabel)) {
                            columns = new ArrayList<>();
                            columnMap.put(columnLabel, columns);
                        } else {
                            columns = columnMap.get(columnLabel);
                        }
                        columns.add(column);
                    }
                    Iterator<Map.Entry<String, List<column>>> iterator = columnMap.entrySet().iterator();
                    for (int i = 0; i < columnMap.size(); i++) {
                        Map.Entry<String, List<column>> entry = iterator.next();
                        String columnId = "column-" + currentTable.getId() + "-index-" + i;
                        if ((!currentTable.isTable() && !currentTable.isView() && !currentTable.isCursor()
                            && !currentTable.isDatabaseType() && !currentTable.isSchemaType()
                            && !currentTable.isStage() && !currentTable.isSequence()
                            && !currentTable.isDataSource() && !currentTable.isStream()
                            && !currentTable.isFile() && !currentTable.isVariable()) || linkColumnSet
                            .contains(columnId)) {
                            removeTable = false;
                            this.nodes.add(entry.getValue());
                            String str1 = new String(columnContent);
                            str1 = str1.replace("{columnId}", columnId);
                            str1 = str1.replace("{columnPosY}",
                                String.valueOf(35 * showColumnCount));
                            String columnLabel = entry.getKey();
                            if (columnLabel.length() > 25) {
                                String shortLabel = getShortLabel(columnLabel, 25);
                                if (tooltipMap != null) {
                                    tooltipMap.put(shortLabel.replace("\r\n", "\n")
                                        .replace("\n", " "), columnLabel);
                                }
                                columnLabel = shortLabel;
                            }
                            str1 = str1.replace("{columnLabel}",
                                StringEscapeUtils.escapeXml(columnLabel));
                            columnBuffer.append(str1).append("\n");
                            showColumnCount++;
                        }
                    }
                } else {
                    for (int k = 0; k < currentTable.getColumns().size(); k++) {
                        column column = currentTable.getColumns().get(k);
                        String columnParentId = currentTable.getId();
                        String columnId = column.getId();
                        columnId = convertColumnId(tableColumns, columnId, columnParentId);
                        columnId = "column-" + columnId;
                        if (currentTable.isTable() || currentTable.isView() || currentTable.isCursor()
                            || currentTable.isDatabaseType() || currentTable.isSchemaType()
                            || currentTable.isStage() || currentTable.isSequence()
                            || currentTable.isDataSource() || currentTable.isStream() || currentTable.isFile()
                            || currentTable.isVariable() || linkColumnSet
                            .contains(columnId)) {
                            removeTable = false;
                            this.nodes.add(column);
                            String str1 = new String(columnContent);
                            str1 = str1.replace("{columnId}", columnId);
                            str1 = str1.replace("{columnPosY}",
                                String.valueOf(35 * showColumnCount));
                            String columnLabel = column.getName();
                            if (columnLabel.length() > 25) {
                                String shortLabel = getShortLabel(columnLabel, 25);
                                if (tooltipMap != null) {
                                    tooltipMap.put(shortLabel.replace("\r\n", "\n")
                                        .replace("\n", " "), columnLabel);
                                }
                                columnLabel = shortLabel;
                            }
                            str1 = str1.replace("{columnLabel}",
                                StringEscapeUtils.escapeXml(columnLabel));
                            columnBuffer.append(str1).append("\n");
                            showColumnCount++;
                        }
                    }
                }
                if (removeTable) {
                    this.nodes.remove(currentTable);
                    continue;
                }
                if (columnBuffer.toString().trim().length() == 0) {
                    String columnId = "column-" + currentTable.getId();
                    String content1 = new String(columnContent);
                    content1 = content1.replace("{columnId}", columnId);
                    content1 = content1.replace("{columnPosY}", "0");
                    content1 = content1.replace("{columnLabel}", "hide-table-column");
                    content1 = content1.replace("height=\"16\"", "height=\"0\"");
                    columnBuffer.append(content1).append("\n");
                }
                String content = new String(tableContent);
                content = content.replace("{tableId}", "table-" + currentTable
                    .getId());
                String tableLabel = currentTable.getName();
                if (tableLabel.length() > 25) {
                    String shortLabel = getShortLabel(tableLabel, 25);
                    if (tooltipMap != null) {
                        tooltipMap.put(shortLabel.replace("\r\n", "\n")
                            .replace("\n", " "), tableLabel);
                    }
                    tableLabel = shortLabel;
                }
                content = content.replace("{tableLabel}",
                    StringEscapeUtils.escapeXml(tableLabel));
                String columnString = columnBuffer.toString();
                if (hideColumn) {
                    columnString = columnString.replace("height=\"16\"", "height=\"0\"");
                }
                content = content.replace("{columns}", columnString);
                if (currentTable.isView()) {
                    content = content.replace("{contentColor}", "#ff99cc");
                    content = content.replace("{labelColor}", "#ffccff");
                } else if (currentTable.isStage()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isSequence()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isDataSource()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isDatabaseType()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isSchemaType()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isStream()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isFile()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isVariable()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isCursor()) {
                    content = content.replace("{contentColor}", "#87CEFA");
                    content = content.replace("{labelColor}", "#87CEFA");
                } else if (currentTable.isResultSet()) {
                    content = content.replace("{contentColor}", "#009944");
                    content = content.replace("{labelColor}", "#aaffcc");
                } else {
                    content = content.replace("{contentColor}", "#9999ff");
                    content = content.replace("{labelColor}", "#DBDADA");
                }
                tableLinkBuffer.append(content).append("\n");
                containGroup = true;
            }
            graphContent = graphContent.replace("{nodes}", tableLinkBuffer
                .toString());
        } else {
            graphContent = graphContent.replace("{nodes}", tableFullBuffer
                .toString());
        }
        this.nodes.addAll(this.linkIds);
        graphContent = graphContent.replace("{links}", linkBuffer.toString());
        Set<String> dbObjIds = new LinkedHashSet<>();
        dbObjIds.addAll(tableMap.keySet());
        dbObjIds.addAll(processMap.keySet());
        return new Pair3(graphContent, Boolean.valueOf(containGroup), dbObjIds);
    }

    private boolean traceJoin(relationship relationship1, List<relationship> relationships,
                              Map<String, Map<String, List<column>>> tableColumns, int level) {
        targetColumn target = relationship1.getTarget();
        String targetColumnId = target.getId();
        String targetParentId = target.getParent_id();
        targetColumnId = convertColumnId(tableColumns, targetColumnId, targetParentId);
        for (int i = 0; i < relationships.size(); i++) {
            relationship tempRelation = relationships.get(i);
            if (relationship1 != tempRelation) {
                List<sourceColumn> sources = tempRelation.getSources();
                if (sources != null &&
                    relationships.size() * sources.size() > 5000) {
                } else {
                    String tempColumnId = tempRelation.getTarget().getId();
                    String tempParentId = tempRelation.getTarget().getParent_id();
                    tempColumnId = convertColumnId(tableColumns, tempColumnId, tempParentId);
                    if (tempColumnId.equals(targetColumnId)) {
                        if (tempRelation.getType().equals(RelationshipType.join.name())) {
                            return true;
                        }
                        if (tempRelation.getType()
                            .equals(RelationshipType.fdd.name()) &&
                            level < 2 &&
                            traceJoin(tempRelation, relationships, tableColumns, level + 1)) {
                            return true;
                        }
                    }
                    if (sources != null) {
                        for (int j = 0; j < sources.size(); j++) {
                            if (!"constant".equals(((sourceColumn) sources.get(j)).getColumn_type())) {
                                tempColumnId = ((sourceColumn) sources.get(j)).getId();
                                tempParentId = ((sourceColumn) sources.get(j)).getParent_id();
                                tempColumnId = convertColumnId(tableColumns, tempColumnId, tempParentId);
                                if (tempColumnId.equals(targetColumnId)) {
                                    if (tempRelation.getType()
                                        .equals(RelationshipType.join.name())) {
                                        return true;
                                    }
                                    if (tempRelation.getType()
                                        .equals(RelationshipType.fdd.name()) &&
                                        level < 2 &&
                                        traceJoin(tempRelation, relationships, tableColumns, level + 1)) {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    private String convertColumnId(Map<String, Map<String, List<column>>> tableColumns,
                                   String columnId, String parentId) {
        if (tableColumns.containsKey(parentId)) {
            Map<String, List<column>> columnMap = tableColumns.get(parentId);
            Iterator<List<column>> iter = columnMap.values().iterator();
            for (int i = 0; i < columnMap.size(); i++) {
                List<column> columns = iter.next();
                for (int j = 0; j < columns.size(); j++) {
                    column column = columns.get(j);
                    if (column.getId().equals(columnId)) {
                        return parentId + "-index-" + i;
                    }
                }
            }
        }
        if (parentId != null) {
            return parentId + "-id-" + columnId;
        }
        return columnId;
    }

    private String getShortLabel(String label, int length) {
        int index = length / 2 - 1;
        return label.substring(0, index - 1) + "..." + label.substring(label.length() - index + 1);
    }
}
